
package com.huaweicloud.saaslanding.install.properties;

import static com.huaweicloud.saaslanding.install.constant.ModelConstant.DATABASE_PREFIX;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

/**
 * 数据库连接信息配置项
 *
 * @since 2023-03-24
 */
@Data
@Component
@Validated
@ConfigurationProperties(prefix = DATABASE_PREFIX)
public class DatabaseConfig {
    /**
     * 数据库连接信息
     */
    @Valid
    private ConnectionInfo connectionInfo = new ConnectionInfo();

    /**
     * 数据库类型，当前支持rds和gaussDb（GaussDB for MySQL 8.0）
     */
    @NotBlank(message = "数据库类型不能为空")
    @Pattern(regexp = "rds|gaussDb", message = "数据库类型错误")
    private String type;

    /**
     * 端点
     */
    @NotBlank(message = "端点不能为空")
    private String endpoint;

    /**
     * RDS尊享版套餐购买参数
     */
    private ExclusivePackageRds exclusivePackageRds = new ExclusivePackageRds();

    /**
     * GaussDB尊享版套餐购买参数
     */
    @Valid
    private ExclusivePackageGaussDb exclusivePackageGaussDb = new ExclusivePackageGaussDb();

    @Data
    @Validated
    public static class ConnectionInfo {
        /**
         * 内网地址
         */
        @NotEmpty(message = "内网地址(rds.ip)不能为空")
        @Pattern(
            regexp = "^((2((5[0-5])|([0-4]\\d)))|([0-1]?\\d{1,2}))(\\.((2((5[0-5])|([0-4]\\d)))|([0-1]?\\d{1,2}))){3}$",
            message = "内网地址(rds.ip)格式错误")
        private String ip;

        /**
         * 数据库端口
         */
        @NotNull(message = "数据库端口(rds.port)不能为空")
        private Integer port;

        /**
         * 管理员账户名
         */
        @NotEmpty(message = "管理员账户名(rds.name)不能为空")
        private String name;

        /**
         * 管理员密码
         */
        @NotEmpty(message = "管理员密码(rds.password)不能为空")
        private String password;

        /**
         * 默认数据库名
         */
        @NotEmpty(message = "默认数据库名(rds.database)不能为空")
        @Pattern(regexp = "[a-z0-9]([-a-z0-9]*[a-z0-9])?",
            message = "数据库名由小写字母、数字、或字符“-”组成，并且必须以小写字母、数字开头和结尾，当前数据库名不符合要求")
        private String dbName;

        /**
         * 默认实例ID
         */
        @NotEmpty(message = "默认数据库名(rds.instanceId)不能为空")
        private String instanceId;

        /**
         * 默认实例名称
         */
        @NotEmpty(message = "默认实例名称(rds.instanceName)不能为空")
        @Pattern(regexp = "[a-z0-9]([-a-z0-9]*[a-z0-9])?",
            message = "实例名称由小写字母、数字、或字符“-”组成，并且必须以小写字母、数字开头和结尾，当前实例名称不符合要求")
        private String instanceName;
    }

    @Data
    public static class ExclusivePackageRds {
        /**
         * 实例类型
         */
        private String datastoreType;

        /**
         * 实例版本
         */
        private String datastoreVersion;

        /**
         * 数据库密码
         */
        private String password;

        /**
         * 规格码 取值范围：非空
         */
        private String flavorRef;

        /**
         * 磁盘类型
         */
        private String volumeType;

        /**
         * 磁盘大小
         */
        private Integer volumeSize;

        /**
         * 可用区ID
         */
        private String availabilityZone;
    }

    @Data
    @Validated
    public static class ExclusivePackageGaussDb {
        /**
         * 数据库引擎，现在只支持gaussdb-mysql
         */
        @Pattern(regexp = "gaussdb-mysql", message = "数据库引擎目前只支持gaussdb-mysql")
        private String datastoreType = "gaussdb-mysql";

        /**
         * 数据库版本。目前仅支持8.0
         */
        @Pattern(regexp = "8\\.0", message = "数据库版本目前只支持8.0")
        private String datastoreVersion = "8.0";

        /**
         * 实例类型，目前仅支持Cluster。
         */
        @Pattern(regexp = "Cluster", message = "实例类型目前只支持Cluster")
        private String mode = "Cluster";

        /**
         * 磁盘大小。默认值为40，单位GB。取值范围：40~128000，必须为10的整数倍。
         */
        @Pattern(regexp = "([4-9]|[1-9]\\d{1,3}|1[01]\\d{3}|12[1-7]\\d{2}|12800)0", message = "磁盘大小错误")
        private String volumeSize;

        /**
         * 规格码。
         */
        @NotBlank(message = "规格码不能为空")
        private String flavorRef;

        /**
         * 可用区类型,单可用区single或多可用区multi。
         */
        @Pattern(regexp = "single|multi", message = "可用区类型错误")
        private String availabilityZoneMode;

        /**
         * 主可用区。availability-zone-mode为single时，不需配置；为multi时，需要配置
         */
        private String masterAvailabilityZone;

        /**
         * 备节点个数。单次接口调用最多支持创建9个备节点。
         */
        @Max(value = 9, message = "备节点个数最大为9")
        @Min(value = 1, message = "备节点个数最小为1")
        @NotNull(message = "备节点个数不能为空")
        private Integer slaveCount;

        /**
         * 数据库密码。
         * 取值范围：至少包含以下字符的三种：大小写字母、数字和特殊符号~!@#$%^*-_=+?,()&，长度8~32个字符。
         * 建议您输入高强度密码，以提高安全性，防止出现密码被暴力破解等安全风险。如果您输入弱密码，系统会自动判定密码非法。
         */
        @NotBlank(message = "数据库密码不能为空")
        @Pattern(regexp = "^(?=.*\\d)(?=.*[a-zA-Z])(?=.*[~!@#$%^*_=+?,()&-]).{8,32}$", message = "数据库密码格式错误")
        private String password;
    }
}
